// keel_grt.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"

#include "backstage_runtime_audio_DirectShowPlayer.h"
#include "backstage_runtime_ctrl_KeyboardDeviceImpl.h"
#include "backstage_runtime_KeelRuntimeWindowsImpl.h"

struct WINDOWPLACEMENTEX:public WINDOWPLACEMENT
{
	HWND hWnd;
};
//////////////////////////////////////////////////////////////////////////

IGraphBuilderPtr g_graphBuilder;
IMediaControlPtr g_mediaControl;
IMediaSeekingPtr g_mediaSeeking;
IBasicAudioPtr g_basicAudio;
IMediaEventExPtr g_mediaEvent;
HWND g_hWnd;
HICON g_hIcon;
HDC g_hDC;
int g_iPlay;
BOOL g_bLoop;
int g_iRuntimeState;//1:Distribution Runtime ,2:Development Runtime
BYTE g_KeyState[256];
BOOL g_bIMEEnable;
HWND g_hIMENotifyWnd;
jobject g_PassiveInputMethodRequests;
jobject g_ActiveInputMethodRequests;
BOOL g_bIMEPassiveMode;
HIMC g_hImc;
BOOL g_bIMEActiveMode;
extern BOOL g_bCursorHide;
jclass g_Cursor_class,g_Cursor_class2;
jmethodID g_Cursor_init;
jfieldID g_Cursor_nativeContext,g_Cursor_nativeContext2;
jfieldID g_Cursor_type;
jclass g_ApplicationEvent_class;
jmethodID g_ApplicationEvent_init;
jclass g_MouseEvent_class;
jmethodID g_MouseEvent_init;
jobject g_MouseEvent;
BOOL g_bMouseEvent_return;
extern BOOL g_bUpdate;
extern int g_iWndState;
BOOL g_bLButtonDown;
POINT g_WndPos;
BOOL g_bHitTestLast;
DWORD g_dwStyle;
MSG g_Msg,*g_pMsg;
DWORD g_uMouseMetrics;
int g_iMouseDBClickTime,g_iMouseDBClickWidth,g_iMouseDBClickHeight;
int g_iMouseClickTimeLast;
int g_iMouseClickButtonLast,g_iMouseClickPosXLast,g_iMouseClickPosYLast;
int g_iMouseClickCount;
BOOL g_bMouseMove;
int g_iMousePosXLast,g_iMousePosYLast;
HMENU g_hMenu;
jclass g_ActiveInputMethodRequests_class;
jmethodID g_ActiveInputMethodRequests_getCandidateLocation;
int g_immPosRelatX,g_immPosRelatY;
extern int g_javaKeyMap[256];
extern UINT g_uCodePage;
extern DWORD g_dwPlatformId;
jclass g_KeyEvent_class;
jmethodID g_KeyEvent_init;
//BYTE g_bDBCSLeadByte;
jclass g_String_class;
jmethodID g_String_concat;
WORD g_wLangID;
jclass g_WindowsInputMethod_class;
jmethodID g_WindowsInputMethod_createInputMethodEvent;
jclass g_PassiveInputMethodRequests_class;
jmethodID g_PassiveInputMethodRequests_getCompositionLocation;
jclass g_ResourceBundle_class;
BOOL g_bDisplayMode;
jlong g_PixelFormatId;
extern HINSTANCE g_hInstance;
TCHAR g_windowName;
extern HCURSOR g_hCursor;

// LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
// {
// 	switch(Msg)
// 	{
// 	case WM_CLOSE:
// 		PostMessage(hWnd,MSG_QUIT_REQUESTED,NULL,NULL);
// 		return 0;
// 	case WM_PAINT:
// 		g_bUpdate = TRUE;
// 		break;
// 	case WM_ACTIVATE:
// 		if(LOWORD(wParam)==WA_INACTIVE || HIWORD(wParam))//minimized
// 			g_iWndState = EVENT_DEACTIVATED;
// 		else
// 			g_iWndState = EVENT_ACTIVATED;
// 		break;
// 	case WM_SETCURSOR:
// 		if ( g_bHitTest )
// 		{
// 			if ( !(g_bCursorHide && (LOWORD)lParam == HTCLIENT ))
// 			{
// 				ShowCursor(TRUE);
// 				g_bHitTest = FALSE;
// 			}
// 		}
// 		else
// 		{
// 			if ( g_bCursorHide && (LOWORD)lParam == HTCLIENT )
// 			{
// 				ShowCursor(FALSE);
// 				g_bHitTest = TRUE;
// 			}
// 		}
// 
// 		if ( g_hCursor )
// 			SetCursor(g_hCursor);
// 		break;
// 	case WM_INPUTLANGCHANGE:
// 		g_uCodePage=GetCurrentPageCode(lParam);
// 		break;
// 	case WM_GETMINMAXINFO:
// 		{
// 			MINMAXINFO *mi=reinterpret_cast<LPMINMAXINFO*>(lParam);
// 			mi->ptMaxTrackSize.x=10000;
// 			mi->ptMaxTrackSize.y=10000;
// 			return 0;
// 		}
// 	}
// 	return DefWindowProc(hWnd,Msg,wParam,lParam);
// }

// void RegWndClass()
// {
// 	WNDCLASS WndClass={0};
// 
// 	WndClass.style = CS_OWNDC;
// 	WndClass.lpfnWndProc = WndProc;
// 	WndClass.cbClsExtra = 0;
// 	WndClass.cbWndExtra = 0;
// 	WndClass.hInstance = g_hInstance;
// 	WndClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
// 	WndClass.hCursor = 0;
// 	WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
// 	WndClass.lpszMenuName = 0;
// 	WndClass.lpszClassName = _T("runtimetest_win");
// 
// 	if ( RegisterClass(&WndClass) )
// 	{
// 		WndClass.lpszClassName = _T("runtimetest_full");
// 		RegisterClass(&WndClass);
// 	}
// }

// void SetNotifyWindow(HWND hWnd)
// {
// 	if(g_mediaEvent)
// 		g_mediaEvent->SetNotifyWindow(hWnd,MSG_DSHOW_EVENT,NULL);
// }

// HRESULT InitDShow()
// {
// 	HRESULT ret;
// 	ret=g_graphBuilder.CreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC_SERVER|CLSCTX_INPROC_HANDLER);
// 	if(SUCCEEDED(ret))
// 	{
// 		ret=g_graphBuilder->QueryInterface(&g_mediaControl);
// 		if(SUCCEEDED(ret))
// 		{
// 			ret=g_graphBuilder->QueryInterface(&g_mediaSeeking);
// 			if(SUCCEEDED(ret))
// 			{
// 				ret=g_graphBuilder->QueryInterface(&g_basicAudio);
// 				if(SUCCEEDED(ret))
// 				{
// 					ret=g_graphBuilder->QueryInterface(&g_mediaEvent);
// 					if(SUCCEEDED(ret))
// 						if(g_hWnd)
// 							SetNotifyWindow(g_hWnd);
// 				}
// 			}
// 		}
// 	}
// 	return ret;
// }

// void CloseDShow()
// {
// 	if(g_mediaControl)
// 		g_mediaControl.Release();
// 	if(g_mediaSeeking)
// 		g_mediaSeeking.Release();
// 	if(g_basicAudio)
// 		g_basicAudio.Release();
// 	if(g_graphBuilder)
// 		g_graphBuilder.Release();
// }

// void StopDShow()
// {
// 	if ( g_iPlay && g_mediaControl )
// 		if(SUCCEEDED(g_mediaControl->Stop())) 
// 			g_iPlay = State_Stopped;
// }

// JNIEXPORT jint JNICALL Java_backstage_runtime_audio_DirectShowPlayer_openNative
// (JNIEnv *env, jobject, jstring fname)
// {
// 	g_bLoop = TRUE;
// 	if(InitDShow()<0)
// 		return -1;
// 
// 	LONGLONG duration;
// 	jchar *s=env->GetStringChars(fname,NULL);
// 	if(FAILED(g_graphBuilder->RenderFile(s),NULL)) ||
// 		g_mediaSeeking==NULL ||
// 		FAILED(g_mediaSeeking->IsFormatSupported(TIME_FORMAT_MEDIA_TIME)) ||
// 		FAILED(g_mediaSeeking->SetTimeFormat(TIME_FORMAT_MEDIA_TIME)) ||
// 		FAILED(g_mediaSeeking->GetDuration(&duration)))
// 	{
// 		CloseDShow();
// 		env->ReleaseStringChars(fname,s);
// 		return -1;
// 	}
// 	env->ReleaseStringChars(fname,s);
// 	return duration/10000;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_startNative
// (JNIEnv *, jobject)
// {
// 	if(g_mediaControl)
// 		if(SUCCEEDED(g_mediaControl->Run()))
// 			g_iPlay=State_Running;
// 
// 	return TRUE;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_stopNative
// (JNIEnv *, jobject)
// {
// 	if(g_iPlay==State_Running && g_mediaControl)
// 		if(SUCCEEDED(g_mediaControl->Pause()))
// 			g_iPlay=State_Paused;
// 
// 	return TRUE;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_setVolumeNative
// (JNIEnv *, jobject, jfloat x)
// {
// 	if(g_basicAudio)
// 	{
// 		double v;
// 		if(x==0.0)
// 			v=-10000.0;
// 		else
// 			v=log10(x)*20.0*100.0;
// 		return SUCCEEDED(g_basicAudio->put_Volume(v));
// 	}
// 	return FALSE;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_seekNative
// (JNIEnv *, jobject, jint p)
// {
// 	if(g_mediaSeeking)
// 	{
// 		LONGLONG pos=10000i64*p;
// 		return SUCCEEDED(g_mediaSeeking->SetPositions(&pos,AM_SEEKING_AbsolutePositioning,NULL,0));
// 	}
// 	return FALSE;
// }

// JNIEXPORT jint JNICALL Java_backstage_runtime_audio_DirectShowPlayer_getCurrentTimeNative
// (JNIEnv *, jobject)
// {
// 	LONGLONG pos;
// 	if(g_mediaSeeking &&
// 		SUCCEEDED(g_mediaSeeking->GetPositions(&pos,NULL)))
// 			return pos/10000;
// 	
// 	return -1;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_audio_DirectShowPlayer_setRateNative
// (JNIEnv *, jobject, jfloat r)
// {
// 	double rate;
// 	if(g_mediaSeeking &&
// 		SUCCEEDED(g_mediaSeeking->GetRate(&rate)))
// 			return SUCCEEDED(g_mediaSeeking->SetRate(r));
// 
// 	return FALSE;
// }

//////////////////////////////////////////////////////////////////////////
HGLRC g_cont;
jclass g_BigInteger;
jmethodID g_BigInteger_testBit;

// void DevModeMake(JNIEnv* env,jobject devin,DEVMODE *devout)
// {
// 	jclass devc=env->GetObjectClass(devin);
// 	jfieldID devc_width=env->GetFieldID(devc,"width", "I");
// 	jfieldID devc_height=env->GetFieldID(devc,"height", "I");
// 	jfieldID devc_bitdepth=env->GetFieldID(devc,"bitdepth", "I");
// 	jfieldID devc_refreshrate=env->GetFieldID(devc,"refreshrate", "I");
// 	int width=env->GetIntField(devin,devc_width);
// 	int height=env->GetIntField(devin,devc_height);
// 	int bitdepth=env->GetIntField(devin,devc_bitdepth);
// 	int refreshrate=env->GetIntField(devin,devc_refreshrate);
// 	memset(devout,0,sizeof(DEVMODE));DM_ORIENTATION
// 	devout->dmFields = (-(bitdepth!=-1) & DM_BITSPERPEL) | 
// 						(-(refreshrate!=-1) & DM_DISPLAYFREQUENCY) | 
// 						DM_PELSHEIGHT|DM_PELSWIDTH;
// 	devout->dmPelsWidth = width;
// 	devout->dmSize = sizeof(DEVMODE);
// 	devout->dmPelsHeight = height;
// 	devout->dmBitsPerPel = (bitdepth!=-1) ? bitdepth : 0;
// 	devout->dmDisplayFrequency = (refreshrate!=-1) ? refreshrate : 0;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1isDisplayAvailable
// (JNIEnv *env, jobject, jobject devin)
// {
// 	DEVMODE DevMode;
// 	DevModeMake(env,devin,&DevMode);
// 	return ChangeDisplaySettings(&DevMode, CDS_TEST) == FALSE;
// }

// JNIEXPORT jlong JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createGraphicsNative
// (JNIEnv *env, jobject, jobject pf)
// {
// 	if(g_hWnd && g_hDC)
// 	{
// 		jclass pfc=env->GetObjectClass(pf);
// 		jfieldID pf_nativeref=env->GetFieldID("nativeref","J");
// 		int ipf=env->GetLongField(pf,pf_nativeref);
// 		PIXELFORMATDESCRIPTOR ppfd;
// 		if(DescribePixelFormat(g_hDC,ipf,sizeof(ppfd),&ppfd))
// 		{
// 			if(SetPixelFormat(g_hDC,ipf,&ppfd))
// 			{
// 				g_cont=wglCreateContext(g_hDC);
// 				return reinterpret_cast<jlong>(g_cont);
// 			}
// 		}
// 	}
// 	return 0;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_makeCurrentNative
// (JNIEnv *, jobject)
// {
// 	if(g_hWnd && g_cont && g_hDC)
// 		return wglMakeCurrent(g_hDC,g_cont);
// 
// 	return FALSE;
// }

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_freeGraphicsNative
(JNIEnv *, jobject)
{
	//if(g_hWnd && g_cont)
			wglMakeCurrent(0, 0);
}

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1swapBuffers
// (JNIEnv *, jobject)
// {
// 	if ( g_hWnd && g_cont && g_hDC)
// 			SwapBuffers(g_hDC);
// }

// JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getScreenPtrNative
// (JNIEnv *, jobject)
// {
// 	return g_hWnd;
// }

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_isGraphicsActive
// (JNIEnv *, jobject)
// {
// 	if ( g_hWnd && g_cont )
// 		return g_cont == wglGetCurrentContext();
// 
// 	return FALSE;
// }

//////////////////////////////////////////////////////////////////////////
void sgenrand(DWORD s, DWORD *mt, int &mti)
{
	int x = s;
	for(int i=0;i<624;++i)
	{
		mt[i] = x & 0xFFFF0000;
		x = 69069 * x + 1;
		mt[i] |= (x & 0xFFFF0000) >> 16;
		x = 69069 * x + 1;
	}

	mti = 624;
}
DWORD genrand(DWORD *mt, int &mti)
{
	DWORD y;
	static DWORD mag01[]={0, 0x9908B0DF};

	if ( mti >= 624 )
	{
		if ( mti == 625 )
			sgenrand(4357, mt, mti);
		int kk;
		for (kk=0;kk<227;++kk) {
			y = mt[kk]^((mt[kk]^mt[kk+1])&0x7FFFFFFF);
			mt[kk] = mt[kk+397] ^ (y >> 1) ^ mag01[y & 1];
		}
		for (;kk<623;++kk) {
			y = mt[kk]^((mt[kk]^mt[kk+1])&0x7FFFFFFF);
			 //(mt[kk]&0x80000000)|(mt[kk+1]&0x7FFFFFFF);
			mt[kk] = mt[kk-227] ^ (y >> 1) ^ mag01[y & 1];
		}
		y = mt[623]^((mt[623]^mt[0])&0x7FFFFFFF);
		mt[623] = mt[396] ^ (y >> 1) ^ mag01[y & 0x1];

		mti = 0;
	}
	y = mt[mti++];

	y ^= (y >> 11);
	y ^= ((y & 0xFF3A58AD) << 7);
	y ^= ((y & 0xFFFFDF8C) << 15);
	y ^= (y >> 18);

	return y;
}
//////////////////////////////////////////////////////////////////////////
int g_mti=625;
DWORD g_mt[624];
// 
// BOOL HashCheck(JNIEnv* env,jstring s,int a1,int l1,int a2,int l2,int x)
// {
// 	if(g_BigInteger==NULL)
// 	{
// 		jclass bic=env->FindClass("java/math/BigInteger");
// 		if(bic==NULL)
// 			return FALSE;
// 		g_BigInteger=env->NewGlobalRef(bic);
// 	}
// 
// 	jmethodID BigInteger_init=env->GetMethodID("<init>", "(Ljava/lang/String;I)V");
// 	jobject bigint=env->NewObject(g_BigInteger,BigInteger_init,s,36);
// 	if(env->ExceptionOccurred())
// 	{
// 		env->ExceptionClear();
// 		return FALSE;
// 	}
// 	
// 	if(bigint==NULL)
// 		return FALSE;
// 
// 	if(g_BigInteger_testBit==NULL)
// 	{
// 		g_BigInteger_testBit = env->GetMethodID(g_BigInteger, "testBit", "(I)Z");
// 		if(g_BigInteger_testBit==NULL)
// 			return FALSE;
// 	}
// 	int k1=0,k2=0;
// 	for(int i=0;i<l1;++i)
// 		if(env->CallBooleanMethod(bigint,g_BigInteger_testBit,a1[i]))
// 			k1|=1<<i;
// 	for(int i=0;i<l2;++i)
// 		if(env->CallBooleanMethod(bigint,g_BigInteger_testBit,a2[i]))
// 			k2|=1<<i;
// 
// 	sgenrand(k1,g_mt,g_mti);
// 	if(x<=0)
// 		return FALSE;
// 	
// 	int xx=0;
// 	while(genrand(g_mt,g_mti)!=k2)
// 		if(++xx>=x)
// 			return FALSE;
// 
// 	return TRUE;
// }

int g_hashmapA1[]={6, 74, 32, 15, 22, 38, 26, 51, 24, 37, 31, 77, 41, 14,40, 48};
int g_hashmapB1[]={ 52, 43, 42, 61, 29, 68, 47, 7, 64, 73, 70, 45, 62, 34,
					20, 57, 17, 78, 11, 8, 72, 46, 9, 79, 3, 30, 0, 69,
					4, 59, 16, 36, 21, 63, 50, 65, 53, 35, 66, 13, 27, 5,
					71, 19, 75, 39, 2, 1, 25, 44, 12, 18, 58, 76, 60, 23,
					28, 56, 49, 55, 10, 33, 67, 54};
int g_hashmapA2[]={72, 34, 18, 58, 51, 60, 52, 27, 14, 40, 50, 6, 45, 5,2, 48};
int g_hashmapB2[]={ 56, 79, 33, 59, 11, 17, 4, 32, 8, 20, 69, 38, 23, 42,
					49, 71, 26, 39, 77, 55, 41, 10, 22, 25, 21, 57, 1, 0,
					13, 46, 78, 62, 16, 43, 12, 67, 54, 70, 44, 53, 73,
					29, 37, 74, 7, 30, 66, 31, 65, 19, 47, 15, 36, 61, 24,
					3, 9, 63, 64, 68, 75, 35, 76, 28};

// JNIEXPORT jboolean JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_initRuntimeNative
// (JNIEnv *env, jobject, jstring s1, jstring s2)
// {
// 	g_iRuntimeState=0;
// 	if(s1 && HashCheck(env, s1, g_hashmapA1, 16, g_hashmapB1, 64, 50))
// 	{
// 		g_iRuntimeState=1;
// 		return TRUE;
// 	}
// 	
// 	if(s2 && HashCheck(env, s2, g_hashmapA2, 16, g_hashmapB2, 64, 50))
// 	{
// 		g_iRuntimeState=2;
// 		return TRUE;
// 	}
// 
// 	return FALSE;
// }

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_showLogoNative
(JNIEnv *, jobject)
{
}

JNIEXPORT jstring JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getJavaCommand
(JNIEnv *env, jobject)
{
	return env->NewString(_T("java"),4);
}

JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getSysCursorWidth
(JNIEnv *, jobject)
{
	return GetSystemMetrics(SM_CXCURSOR);
}

JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getSysCursorHeight
(JNIEnv *, jobject)
{
	return GetSystemMetrics(SM_CYCURSOR);
}
// 
// HBITMAP CreateDIBitmapFromBuf(HWND hWnd,DWORD* src,int widths,int widthd,int height)
// {
// 	if(hWnd==NULL)
// 		hWnd=GetDesktopWindow();
// 
// 	HDC hdc=GetDC(hWnd);
// 	if(hdc==NULL)
// 		return NULL;
// 
// 	BYTE tmp[1024+sizeof(BITMAPINFOHEADER)]={0};
// 	BITMAPINFO *bmi=reinterpret_cast<BITMAPINFO *>(tmp);
// 	bmi->bmiHeader.biWidth=widthd;
// 	bmi->bmiHeader.biSize = sizeof(bmi->bmiHeader);
// 	bmi->bmiHeader.biHeight = -height;
// 	bmi->bmiHeader.biPlanes = 1;
// 	bmi->bmiHeader.biBitCount = 24;
// 	bmi->bmiHeader.biCompression = 0;
// 	BYTE *pjBits=NULL;
// 	HBITMAP dib=CreateDIBSection(bmi, 0, &pjBits, 0, 0);
// 
// 	HBITMAP ret=NULL;
// 	if(pjBits)
// 	{
// 		DWORD *s=src;
// 		int stride=(widthd*3+3)&~3;
// 		for(int y=0;y<height;++y)
// 		{
// 			BYTE *d=pjBits+y*stride;
// 			for(int x=0;x<widths;++x,++s,d+=3)
// 			{
// 				d[0]=(BYTE)(*s);
// 				d[1]=(BYTE)((*s)>>8);
// 				d[2]=(BYTE)((*s)>>16);
// 			}
// 		}
// 
// 		ret=CreateDIBitmap(hdc,&bmi->bmiHeader,CBM_INIT,pjBits,bmi,0);
// 		GdiFlush();
// 	}
// 	DeleteObject(dib);
// 	ReleaseDC(hdc);
// 	return ret;
// }

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setIconImageFromIntRasterData
// (JNIEnv *env, jobject, jintArray color, jbyteArray mask, jint widths, jint widthd, jint height)
// {
// 	if(g_hWnd && IsIconic(g_hWnd))
// 		InvalidateRect(g_hWnd,NULL,TRUE);
// 	if(g_hIcon)
// 	{
// 		DestroyIcon(g_hIcon);
// 		g_hIcon=NULL;
// 	}
// 
// 	if(color)
// 	{
// 		HBITMAP hMask=NULL;
// 		if(mask)
// 		{
// 			void* pMask=env->GetPrimitiveArrayCritical(mask,NULL);
// 			if(pMask)
// 			{
// 				hMask=CreateBitmap(widthd,height,1,1,pMask);
// 				env->ReleasePrimitiveArrayCritical(mask,pMask,0);
// 			}
// 		}
// 		else
// 		{
// 			BYTE *pMask=new BYTE[(widthd*height+7)/8];
// 			memset(pMask,0,(widthd*height+7)/8);
// 			hMask=CreateBitmap(widthd,height,1,1,pMask);
// 			GdiFlush();
// 			delete[] pMask;
// 		}
// 
// 		HBITMAP hColor=NULL;
// 		DWORD* pColor=(DWORD*)env->GetPrimitiveArrayCritical(color,NULL);
// 		if(pColor)
// 		{
// 			hColor=CreateDIBitmapFromBuf(g_hWnd,pColor,widths,widthd,height);
// 			env->ReleasePrimitiveArrayCritical(color,pColor,0);
// 		}
// 
// 		if(hMask && hColor)
// 		{
// 			ICONINFO  piconinfo={0};
// 			piconinfo.xHotspot = 0;
// 			piconinfo.yHotspot = 0;
// 			piconinfo.hbmMask = hMask;
// 			piconinfo.hbmColor = hColor;
// 			piconinfo.fIcon = 1;
// 			g_hIcon = CreateIconIndirect(&piconinfo);
// 		}
// 
// 		if(hMask)
// 			DeleteObject(hMask);
// 		if(hColor)
// 			DeleteObject(hColor);
// 	}
// 	if(g_hWnd)
// 	{
// 		PostMessage(g_hWnd, WM_SETICON, 0, (LPARAM)g_hIcon);
// 		PostMessage(g_hWnd, WM_SETICON, 1, (LPARAM)g_hIcon);
// 	}
// }

JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getSysIconWidth
(JNIEnv *, jclass)
{
	return GetSystemMetrics(SM_CXICON);
}

JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getSysIconHeight
(JNIEnv *env, jclass)
{
	return GetSystemMetrics(SM_CYICON);
}

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1enableInputMethods
// (JNIEnv *, jobject, jboolean e)
// {
// 	g_bIMEEnable = e;
// 	if ( g_hIMENotifyWnd )
// 		PostMessage(g_hIMENotifyWnd, MSG_IME_ENABLE, e, 0);
// }

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1setInputMethodPassiveMode
// (JNIEnv *env, jobject, jobject req, jboolean e)
// {
// 	g_bIMEActiveMode = FALSE;
// 
// 	if(g_PassiveInputMethodRequests)
// 	{
// 		env->DeleteGlobalRef(g_PassiveInputMethodRequests);
// 		g_PassiveInputMethodRequests=NULL;
// 	}
// 	
// 	if(req)
// 		g_PassiveInputMethodRequests=env->NewGlobalRef(req);
// 
// 	g_bIMEPassiveMode=e;
// }
// 
// JNIEXPORT jboolean JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1setInputMethodActiveMode
// (JNIEnv *env, jobject, jobject req)
// {
// 	g_bIMEActiveMode = TRUE;
// 
// 	if ( g_ActiveInputMethodRequests )
// 	{
// 		env->DeleteGlobalRef(g_ActiveInputMethodRequests);
// 		g_ActiveInputMethodRequests = 0;
// 	}
// 
// 	if ( req )
// 		g_ActiveInputMethodRequests = env->NewGlobalRef(req);
// }

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setCursorVisibleNative
// (JNIEnv *, jobject, jboolean e)
// {
// 	POINT pos;
// 	RECT rc;
// 	GetCursorPos(&pos);
// 	ScreenToClient(g_hWnd, &pos);
// 	GetClientRect(g_hWnd, &rc);
// 
// 	int ht=HTCLIENT;
// 	if ( rc.left > pos.x || rc.right < pos.x || rc.top > pos.y || rc.bottom < pos.y )
// 		ht = HTCAPTION;
// 
// 	if(e && g_bCursorHide)
// 		g_bCursorHide=FALSE;
// 	else
// 	if(!e && !g_bCursorHide)
// 		g_bCursorHide=TRUE;
// 
// 	PostMessage(g_hWnd,WM_SETCURSOR,0,(LPARAM)ht);
// }

// JNIEXPORT jobject JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createCursorNative
// (JNIEnv *env, jobject, jintArray color, jbyteArray mask, jint widths, jint widthd, jint height, jint x, jint y)
// {
// 	if(widthd!=GetSystemMetrics(SM_CXCURSOR) || height!=GetSystemMetrics(SM_CYCURSOR))
// 		return NULL;
// 
// 	HBITMAP hMask=NULL;
// 	void* pMask=env->GetPrimitiveArrayCritical(mask,NULL);
// 	if(pMask)
// 	{
// 		hMask=CreateBitmap(widthd,height,1,1,pMask);
// 		GdiFlush();
// 		env->ReleasePrimitiveArrayCritical(mask,pMask,0);
// 	}
// 
// 	HBITMAP hColor=NULL;
// 	DWORD* pColor=(DWORD*)env->GetPrimitiveArrayCritical(color,NULL);
// 	if(pColor)
// 	{
// 		hColor=CreateDIBitmapFromBuf(NULL,pColor,widths,widthd,height);
// 		env->ReleasePrimitiveArrayCritical(color,pColor,0);
// 	}
// 
// 	HICON hIcon=NULL;
// 	if(hMask && hColor)
// 	{
// 		ICONINFO  piconinfo={0};
// 		piconinfo.fIcon = 0;
// 		piconinfo.hbmColor = hColor;
// 		piconinfo.hbmMask = hMask;
// 		piconinfo.xHotspot = x;
// 		piconinfo.yHotspot = y;
// 		hIcon = CreateIconIndirect(&piconinfo);
// 	}
// 
// 	if(hMask)
// 		DeleteObject(hMask);
// 	if(hColor)
// 		DeleteObject(hColor);
// 
// 	if(g_Cursor_class==NULL)
// 	{
// 		jclass t=env->FindClass("keel/runtime/Cursor");
// 		if(t==NULL)
// 			return NULL;
// 		g_Cursor_class=env->NewGlobalRef(t);
// 	}
// 
// 	if(g_Cursor_init==NULL)
// 		g_Cursor_init=env->GetMethodID(g_Cursor_class,"<init>", "(I)V");
// 	if(g_Cursor_nativeContext==NULL)
// 		g_Cursor_nativeContext=env->GetFieldID(g_Cursor_class,"nativeContext", "J");
// 	jobject ret=env->NewObject(g_Cursor_class,g_Cursor_init,-1);
// 	env->SetLongField(ret,g_Cursor_nativeContext,hIcon);
// 	return ret;
// }

// HCURSOR GetSystemCursor(int t)
// {
// 	LPTSTR v; 
// 
// 	switch ( t )
// 	{
// 	case 1:
// 		v = IDC_CROSS;
// 		break;
// 	case 2:
// 		v = IDC_IBEAM;
// 		break;
// 	case 3:
// 		v = IDC_WAIT;
// 		break;
// 	case 4:
// 	case 7:
// 		v = IDC_SIZENESW;
// 		break;
// 	case 5:
// 	case 6:
// 		v = IDC_SIZENWSE;
// 		break;
// 	case 8:
// 	case 9:
// 		v = IDC_SIZENS;
// 		break;
// 	case 10:
// 	case 11:
// 		v = IDC_SIZEWE;
// 		break;
// 	case 12:
// 		v = IDC_HAND;
// 		break;
// 	case 13:
// 		v = IDC_SIZEALL;
// 		break;
// 	default:
// 		v = IDC_ARROW;
// 		break;
// 	}
// 	HCURSOR ret = LoadCursor(NULL,v);
// 	if ( ret=NULL )
// 		ret = LoadCursor(NULL,IDC_ARROW);
// 	return ret;
// }

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_setCursorNative
// (JNIEnv *env, jobject, jobject o)
// {
// 	if(g_Cursor_class2==NULL)
// 	{
// 		jclass t=env->FindClass("keel/runtime/Cursor");
// 		if(t==NULL)
// 			return;
// 		g_Cursor_class2=env->NewGlobalRef(t);
// 	}
// 	if(g_Cursor_nativeContext2==NULL)
// 		g_Cursor_nativeContext2=env->GetFieldID(g_Cursor_class2,"nativeContext", "J");
// 
// 	HICON hIcon=env->GetLongField(o,g_Cursor_nativeContext2);
// 	if(hIcon==NULL)
// 	{
// 		if(g_Cursor_type==NULL)
// 			g_Cursor_type=env->GetFieldID(g_Cursor_class2,"type","I");
// 		hIcon=GetSystemCursor(env->GetIntField(o,g_Cursor_type));
// 		env->SetLongField(o,g_Cursor_nativeContext2,hIcon);
// 	}
// 
// 	if(g_hWnd)
// 		PostMessage(g_hWnd,MSG_SETCURSOR,0,(LPARAM)hIcon);
// }

jobject ApplicationEvent_new(JNIEnv*env,int id)
{
	if(g_ApplicationEvent_class==NULL)
	{
		jclass t=env->FindClass("keel/runtime/event/ApplicationEvent");
		if(t==NULL)
			return NULL;
		g_ApplicationEvent_class=env->NewGlobalRef(t);
	}

	if(g_ApplicationEvent_init==NULL)
		g_ApplicationEvent_init=env->GetMethodID(g_ApplicationEvent_class,"<init>", "(I)V");

	return env->NewObject(g_ApplicationEvent_class,g_ApplicationEvent_init,id);
}
// jobject MouseEvent_new(JNIEnv*env ,int id, int modifiers, int x, int y, int clickCount, BOOL popupTrigger, int wheelRotation)
// {
// 	if(g_MouseEvent_class==NULL)
// 	{
// 		jclass t=env->FindClass("keel/runtime/event/MouseEvent");
// 		if(t==NULL)
// 			return NULL;
// 		g_MouseEvent_class=env->NewGlobalRef(t);
// 	}
// 
// 	if(g_MouseEvent_init==NULL)
// 		g_MouseEvent_init=env->GetMethodID(g_MouseEvent_class,"<init>", "(IIIIIZI)V");
// 
// 	return env->NewObject(g_MouseEvent_class,g_MouseEvent_init,id,modifiers,x,y,clickCount,popupTrigger,wheelRotation);
// }

// jobject OnMouseDown(JNIEnv *env,int b,int x,int y)
// {
// 	if ( (g_uMouseMetrics & 1)==0 )
// 	{
// 		g_uMouseMetrics |= 1;
// 		g_iMouseDBClickTime = GetDoubleClickTime();
// 	}
// 	if ( (g_uMouseMetrics & 2) ==0)
// 	{
// 		g_uMouseMetrics |= 2;
// 		g_iMouseDBClickWidth = GetSystemMetrics(SM_CXDOUBLECLK);
// 	}
// 	if ( (g_uMouseMetrics & 4)==0 )
// 	{
// 		g_uMouseMetrics |= 4;
// 		g_iMouseDBClickHeight = GetSystemMetrics(SM_CYDOUBLECLK);
// 	}
// 	
// 	int t = timeGetTime();
// 	if ( g_iMouseClickButtonLast != b ||
// 		(t - g_iMouseClickTimeLast) > g_iMouseDBClickTime ||
// 		abs(x - g_iMouseClickPosXLast) > g_iMouseDBClickWidth ||
// 		abs(y - g_iMouseClickPosYLast) > g_iMouseDBClickHeight )
// 	{
// 		g_iMouseClickCount = 1;
// 		g_iMouseClickButtonLast = b;
// 		g_iMouseClickPosXLast = x;
// 		g_iMouseClickPosYLast = y;
// 	}
// 	else
// 		++g_iMouseClickCount;
// 
// 	g_iMouseClickTimeLast = t;
// 	g_bMouseMove = FALSE;
// 
// 	if ( GetCapture() != g_hWnd )
// 		SetCapture(g_hWnd);
// 
// 	return MouseEvent_new(env, EVENT_MOUSE_PRESSED, GetModKeyState(b), x, y, g_iMouseClickCount, FALSE, 0);
// }

// jobject OnMouseUp(JNIEnv *env,int b,int x,int y,WPARAM wParam)
// {
// 	if(g_bMouseMove==FALSE)
// 		g_MouseEvent=env->NewGlobalRef(
// 			MouseEvent_new(env,EVENT_MOUSE_CLICKED,GetModKeyState(b),x,y,g_iMouseClickCount,FALSE,0));
// 	g_bMouseMove=FALSE;
// 
// 	if(GetCapture()==g_hWnd && wParam&(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)==0)
// 		ReleaseCapture();
// 
// 	return MouseEvent_new(env,EVENT_MOUSE_RELEASED,GetModKeyState(b),x,y,g_iMouseClickCount,b==3,0);
// }

// jobject OnMouseMove(JNIEnv *env,int x,int y,WPARAM wParam)
// {
// 	if(x==g_iMousePosXLast && y==g_iMousePosYLast)
// 		return 0;
// 	else
// 	{
// 		g_iMousePosXLast=x;
// 		g_iMousePosYLast=y;
// 
// 		int t=EVENT_MOUSE_MOVED;
// 		if(wParam&(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))
// 		{
// 			g_bMouseMove=TRUE;
// 			t=EVENT_MOUSE_DRAGGED;
// 		}
// 		return MouseEvent_new(env,t,GetModKeyStateFromIndicator(wParam),x,y,0,FALSE,0);
// 	}
// }

// jobject OnMouseWheel(JNIEnv*env,int x,int y,DWORD vk,int w)
// {
// 	POINT pos={x,y};
// 	ScreenToClient(g_hWnd,&pos);
// 	return MouseEvent_new(env,EVENT_MOUSE_WHEEL_MOVED,GetModKeyStateFromIndicator(vk),pos.x,pos.y,0,FALSE,(w>0)?EVENT_WHEEL_FORWARD:EVENT_WHEEL_BACKWARD);
// }

bool MyGetMessage(MSG* msg)
{
	UINT m=msg->message;
	WPARAM wParam=msg->wParam;

	return !((m >= aaaaaa0x8960 && m <= aaaaaaaa0x896A)
		|| (m == WM_SYSKEYUP && (wParam == VK_MENU || wParam == VK_F10) && g_hMenu==NULL)
		|| (m == WM_SYSCHAR && wParam == _T('2'))
		|| (g_bIMEActiveMode && (m == WM_IME_KEYLAST || m == WM_IME_STARTCOMPOSITION || m == WM_IME_ENDCOMPOSITION))
		|| m == WM_CLOSE
		|| ((m == WM_NCLBUTTONDOWN || m == WM_NCRBUTTONDOWN || m == WM_RBUTTONUP) && wParam!=(MK_LBUTTON|MK_MBUTTON|MK_RBUTTON) && !(wParam >= HTSIZEFIRST && wParam <=HTSIZELAST)));
}
// void MyImeSetCandidateWindow(JNIEnv*env,int i)
// {
// 	CANDIDATEFORM cand={0};
// 	cand.dwIndex=i;
// 	cand.dwStyle=CFS_CANDIDATEPOS;
// 
// 	if(g_ActiveInputMethodRequests==NULL)
// 		return ImmSetCandidateWindow(g_hImc,&cand);
// 
// 	if(g_ActiveInputMethodRequests_class==NULL)
// 	{
// 		jclass t=env->GetObjectClass(g_ActiveInputMethodRequests_class);
// 		if(t==NULL)
// 			return;
// 		g_ActiveInputMethodRequests_class=env->NewGlobalRef(t);
// 	}
// 	if(g_ActiveInputMethodRequests_getCandidateLocation==NULL)
// 		g_ActiveInputMethodRequests_getCandidateLocation=env->GetMethodID( "getCandidateLocation", "()[I");
// 
// 	jarray ret=(jarray)env->CallObjectMethod(g_ActiveInputMethodRequests,g_ActiveInputMethodRequests_getCandidateLocation);
// 	if(ret && env->GetArrayLength(ret)>=2)
// 	{
// 		jint buf[2];
// 		env->GetIntArrayRegion(ret,0,2,buf); 
// 		cand.ptCurrentPos.x = buf[0] + g_immPosRelatX;
// 		cand.ptCurrentPos.y = buf[1] + g_immPosRelatY;
// 	}
// 
// 	return ImmSetCandidateWindow(g_hImc,&cand);
// }

// void OnImeNotify(JNIEnv* env,WPARAM cmd,LPARAM argv)
// {
// 	if(cmd==IMN_OPENCANDIDATE)
// 	{
// 		for(int i=0,j=1;i<32;++i,j+=j)
// 			if(j & argv)
// 				MyImeSetCandidateWindow(env,i);
// 	}
// }
// void ImeEnable(BOOL e)
// {
// 	if(e)
// 	{
// 		ImmAssociateContext(g_hIMENotifyWnd, g_hImc);
// 	}
// 	else
// 	{
// 		ImmNotifyIME(g_hImc, NI_COMPOSITIONSTR,CPS_CANCEL,0);
// 		ImmAssociateContext(g_hIMENotifyWnd, 0);
// 	}
// }

// jobject KeyEvent_new(JNIEnv *env,int id, int modifiers, int keyCode, jchar keyChar)
// {
// 	if(g_KeyEvent_class==NULL)
// 	{
// 		jclass t=env->FindClass("keel/runtime/event/KeyEvent");
// 		if(t==NULL)
// 			return NULL;
// 		g_KeyEvent_class=env->NewGlobalRef(t);
// 	}
// 	if(g_KeyEvent_init==NULL)
// 		g_KeyEvent_init=env->GetMethodID(g_KeyEvent_class,"<init>", "(IIIC)V");
// 	return env->NewObject(g_KeyEvent_class,g_KeyEvent_init,id,modifiers,keyCode,keyChar);
// }

// jobject OnKeyEvent(JNIEnv*env, WPARAM wParam,int id)
// {
// 	if(wParam==VK_PROCESSKEY)
// 		return 0;
// 
// 	int mod=GetModKeyState(0);
// 	int javakey=g_javaKeyMap[wParam];
// 
// 	switch(wParam)
// 	{
// 	case VK_KANA:
// 		if(GetKeyboardLayout(0) == LANGID_JAPANESE && GetKeyboardType(0) == 7)
// 			javakey=JAVA_VK_KANA_LOCK;
// 		break;
// 	case VK_CONVERT:
// 		if(mod&STATE_SHIFT_MASK)
// 			javakey=JAVA_VK_PREVIOUS_CANDIDATE;
// 		else
// 		if(mod&STATE_ALT_MASK)
// 			javakey=JAVA_VK_ALL_CANDIDATES;
// 		break;
// 	case VK_DBE_ALPHANUMERIC:
// 		if(mod&STATE_ALT_MASK)
// 			javakey=JAVA_VK_CODE_INPUT;
// 		break;
// 	}
// 	
// 	if(javakey)
// 		return KeyEvent_new(env,id,mod,javakey,GetJavaKeyChar(mod,javakey));
// 
// 	return NULL;
// }

jobject OnKeyChar(JNIEnv*env,WPARAM wParam,WORD flag,BOOL sys)
{
// 	if(g_bDBCSLeadByte==0 && IsDBCSLeadByteEx(g_uCodePage,wParam))
// 	{
// 		g_bDBCSLeadByte=wParam;
// 		return NULL;
// 	}
	if(wParam<0x20)
		return NULL;

	int mod=GetModKeyState(0);
	if(sys==FALSE && flag & 0x2000)// ALT key 
		mod=mod&(~STATE_CTRL_MASK)&(~STATE_ALT_MASK)|STATE_ALT_GRAPH_MASK;

// 	BYTE dbcs[2];
// 	WCHAR keychar[2]={0};
// 	int dbcsLen;
// 	if(g_bDBCSLeadByte)
// 	{
// 		dbcs[0]=g_bDBCSLeadByte;
// 		dbcs[1]=wParam;
// 		dbcsLen=2;
// 		g_bDBCSLeadByte=0;
// 	}
// 	else
// 	{
// 		dbcs[0]=wParam;
// 		dbcsLen=1;
// 	}
// 	MultiByteToWideChar(g_uCodePage,0,dbcs,dbcsLen,keychar,1);
	return KeyEvent_new(env,EVENT_KEY_TYPED,mod,0,wParam);
}

// int MyImeGetCompositionString(HIMC imc,int id,void **pout)
// {
// 	int len=ImmGetCompositionString(imc,id,NULL,NULL);
// 	BYTE *ret=new BYTE[len];
// 	ImmGetCompositionString(imc,id,ret,len);
// 	*pout=ret;
// 	return len;
// }

// int *sub_10008130(TCHAR *s,int len)
// {
// 	int *ret=new int[len+1];
// 	int i;
// 	for(i=0;i<len;)
// }

// int ImeGetSubString(JNIEnv *env,int strLen,int* clause,int clauseLen,
// 				 TCHAR *readstr,int readstrLen,int *readclause,int readclauseLen,
// 				 jstring **psout)
// {
// 	if(strLen==0 || clauseLen==0 || clauseLen!=readclauseLen || 
// 		clause[0]!=0 || clause[clauseLen]!=strLen || 
// 		readclause[0]!=0 || readclause[readclauseLen]!=readstrLen)
// 	{
// 		*psout=NULL;
// 		return 0;
// 	}
// 
// 	jstring *sout=new jstring[readclauseLen];
// 
// 	for(int i=0;i<readclauseLen;++i)
// 	{
// 		int p=readclause[i];
// 		int q=readclause[i+1];
// 		if(p>=q || q> readstrLen)
// 		{
// 			sout[i]=env->NewString(NULL,0);
// 			continue;
// 		}
// 		int n=q-p;
// 		if(PRIMARYLANGID(g_wLangID)==LANGID_JAPANESE)
// 		{
// 			int len=LCMapString(LCID_JAPANESE,LCMAP_FULLWIDTH,p,n,NULL,0);
// 			TCHAR *tmp=new TCHAR[len];
// 			LCMapString(LCID_JAPANESE,LCMAP_FULLWIDTH,p,n,tmp,len);
// 			sout[i]=env->NewString(tmp,len);
// 			delete[] tmp;
// 			continue;
// 		}
// 		sout[i]=env->NewString(p,n);
// 	}
// 	*psout=sout;
// 	return readclauseLen;
// }

// int ImeGetAttVector(BYTE* attr,int attrLen,int strLen,int** pout1,BYTE** pout2)
// {
// 	if(strLen==0 || attrLen!=strLen)
// 	{
// 		*pout1=NULL;
// 		*pout2=NULL;
// 		return 0;
// 	}
// 
// 	int* out1=new int[strLen+1];
// 	BYTE* out2=new BYTE[strLen];
// 	out1[0]=0;
// 	out2[0]=attr[0];
// 	int j=0;
// 	for(int i=1;i<attrLen;++i)
// 	{
// 		if(attr[i]!=out2[j])
// 		{
// 			++j;
// 			out1[j]=i;
// 			out2[j]=attr[i];
// 		}
// 	}
// 	out1[++j]=strLen;
// 	*pout1=out1;
// 	*pout2=out2;
// 	return j;
// }

// jobject InputMethodEvent_new(JNIEnv*env,int id, int* clause,int clauseLen,jstring str,jstring* subStrings,int attrLen,int* attrClause,BYTE* attr,int commitedTextLength, int caretPos, int visiblePos)
// {
// 	jintArray clauseBoundary=NULL;
// 	jobjectArray clauseReading=NULL;
// 	if(clauseLen && clause && subStrings)
// 	{
// 		clauseBoundary=env->NewIntArray(clauseLen+1);
// 		env->SetIntArrayRegion(clauseBoundary,0,clauseLen+1,clause);
// 		if(g_String_class==0)
// 		{
// 			jclass t=env->FindClass("java/lang/String");
// 			if(t==NULL)
// 				return NULL;
// 			g_String_class=env->NewGlobalRef(t);
// 		}
// 		clauseReading=env->NewObjectArray(clauseLen,g_String_class,NULL);
// 		for(int i=0;i<clauseLen;++i)
// 			env->SetObjectArrayElement(clauseReading,i,subStrings[i]);
// 	}
// 
// 	jintArray attributeBoundary=NULL;
// 	jbyteArray attributeValue=NULL;
// 	if(attrLen && attrClause && attr)
// 	{
// 		attributeBoundary=env->NewIntArray(attrLen+1);
// 		env->SetIntArrayRegion(attributeBoundary,0,attrLen+1,attrClause);
// 		attributeValue=env->NewByteArray(attrLen);
// 		env->SetByteArrayRegion(attributeValue,0,attrLen,attr);
// 	}
// 
// 	if(g_WindowsInputMethod_class==NULL)
// 	{
// 		jclass t=g_WindowsInputMethod_class=env->FindClass("backstage/runtime/im/WindowsInputMethod");
// 		if(t==NULL)
// 			return NULL;
// 		g_WindowsInputMethod_class=env->NewGlobalRef(t);
// 	}
// 	if(g_WindowsInputMethod_createInputMethodEvent==NULL)
// 		g_WindowsInputMethod_createInputMethodEvent=env->GetStaticMethodID(g_WindowsInputMethod_class,"createInputMethodEvent",
// 		"(ILjava/lang/String;[I[Ljava/lang/String;[I[BIII)Lkeel/runtime/event/InputMethodEvent;");
// 	return env->CallStaticObjectMethod(g_WindowsInputMethod_class,g_WindowsInputMethod_createInputMethodEvent,
// 		id,str,clauseBoundary,clauseReading,attributeBoundary,attributeValue,commitedTextLength,caretPos,visiblePos);
// }

// jobject ImeComposition(JNIEnv* env,WORD dbcs,LPARAM lParam)
// {
// 	if(g_bIMEActiveMode==FALSE)
// 		return NULL;
// 
// 	jobject ret=NULL;
// 
// 	jstring *resSubStrings=NULL,resString=NULL;
// 	jstring *compSubStrings=NULL,compString=NULL;
// 	int resStringLen=0;
// 	int compStringLen=0;
// 	int *resClause=NULL;
// 	int *compClause=NULL;
// 	int resClauseLen=0;
// 	int compClauseLen=0;
// 	BYTE *compAttr=NULL;
// 	int *compAttrClause=NULL;
// 	int compAttrLen=0;
// 	WORD cursorPos;
// 
// 	if(lParam & (GCS_RESULTREADSTR|GCS_RESULTREADCLAUSE|GCS_RESULTSTR|GCS_RESULTCLAUSE))
// 	{
// 		TCHAR *str=NULL,*readstr=NULL;
// 		int *readclause=NULL;
// 		resStringLen=MyImeGetCompositionString(g_hImc,GCS_RESULTSTR,&str)/sizeof(TCHAR);
// 		int clauseLen=MyImeGetCompositionString(g_hImc,GCS_RESULTCLAUSE,&resClause)/sizeof(int)-1;
// 		int readstrLen=MyImeGetCompositionString(g_hImc,GCS_RESULTREADSTR,&readstr)/sizeof(TCHAR);
// 		int readclauseLen=MyImeGetCompositionString(g_hImc,GCS_RESULTREADCLAUSE,&readclause)/sizeof(int)-1;
// 		
// 		resString=env->NewString(str,resStringLen);
// 		resClauseLen=ImeGetSubString(env,resStringLen,resClause,clauseLen,readstr,readstrLen,readclause,readclauseLen,&resSubStrings);
// 
// 		delete[] str;
// 		delete[] readstr;
// 		delete[] readclause;
// 	}
// 
// 	if(lParam & (GCS_DELTASTART|GCS_CURSORPOS|GCS_COMPCLAUSE|GCS_COMPATTR|GCS_COMPSTR|GCS_COMPREADCLAUSE|GCS_COMPREADATTR|GCS_COMPREADSTR))
// 	{
// 		TCHAR *str=NULL,*readstr=NULL;
// 		int *readclause=NULL;
// 		compStringLen=MyImeGetCompositionString(g_hImc,GCS_COMPSTR,&str)/sizeof(TCHAR);
// 		int clauseLen=MyImeGetCompositionString(g_hImc,GCS_COMPCLAUSE,&compClause)/sizeof(int)-1;
// 		int readstrLen=MyImeGetCompositionString(g_hImc,GCS_COMPREADSTR,&readstr)/sizeof(TCHAR);
// 		int readclauseLen=MyImeGetCompositionString(g_hImc,GCS_COMPREADCLAUSE,&readclause)/sizeof(int)-1;
// 
// 		compString=env->NewString(str,compStringLen);
// 		compClauseLen=ImeGetSubString(env,compStringLen,compClause,clauseLen,readstr,readstrLen,readclause,readclauseLen,&compSubStrings);
// 
// 		cursorPos=ImmGetCompositionString(g_hImc,GCS_CURSORPOS,NULL,0);
// 		
// 		BYTE* attr=NULL;
// 		int attrLen=MyImeGetCompositionString(g_hImc,GCS_COMPATTR,&attr);
// 		compAttrLen=ImeGetAttVector(attr,attrLen,compStringLen,&compAttrClause,&compAttr);
// 
// 		delete[] str;
// 		delete[] readstr;
// 		delete[] readclause;
// 		delete[] attr;
// 	}
// 
// 	if(resStringLen==0)
// 	{
// 		if(compStringLen==0)
// 			ret=InputMethodEvent_new(env,EVENT_TEXT_CHANGED,NULL,0,NULL,NULL,0,NULL,NULL,0,0,0);
// 		else
// 			ret=InputMethodEvent_new(env,EVENT_TEXT_CHANGED,compClause,compClauseLen,compString,compSubStrings,
// 			compAttrLen,compAttrClause,compAttr,0,cursorPos,cursorPos);
// 	}
// 	else
// 	{
// 		if(compStringLen==0)
// 			ret=InputMethodEvent_new(env,EVENT_TEXT_CHANGED,resClause,resClauseLen,resString,resSubStrings,
// 			0,NULL,NULL,resStringLen,0,0);
// 		else
// 		{
// 			if(g_String_class==NULL)
// 			{
// 				jclass t=env->GetObjectClass(resString);
// 				g_String_class=env->NewGlobalRef(t);	
// 			}
// 			if(g_String_concat==NULL)
// 				g_String_concat=env->GetMethodID(g_String_class,"concat", "(Ljava/lang/String;)Ljava/lang/String;");
// 
// 			jstring allString=env->CallObjectMethod(resString,g_String_concat,compString);
// 			int allClauseLen=resClauseLen+compClauseLen;
// 			int allLen=resStringLen+compStringLen;
// 
// 			int *allClause=new int[allClauseLen+1];
// 			jstring* allSubStrings=new jstring[allClauseLen];
// 
// 			int j=0;
// 			if(resClauseLen && resClause && resSubStrings)
// 			{
// 				for(int i=0;i<resClauseLen;++i)
// 				{
// 					allClause[j]=resClause[i];
// 					allSubStrings[j]=resSubStrings[i];
// 					++j;
// 				}
// 			}
// 			if(compClauseLen && compClause && compSubStrings)
// 			{
// 				for(int i=0;i<compClauseLen;++i)
// 				{
// 					allClause[j]=compClause[i]+resStringLen;
// 					allSubStrings[j]=compSubStrings[i];
// 					++j;
// 				}
// 			}
// 			allClause[allClauseLen]=allLen;
// 			
// 			int allAttrLen=compAttrLen+1;
// 			int *allAttrClause=new int[allAttrLen+1];
// 			BYTE *allAttr=new BYTE[allAttrLen;
// 			allAttrClause[0]=0;
// 			allAttr[0]=ATTR_CONVERTED;
// 			for(int i=0;i<compAttrLen;++i)
// 			{
// 				allAttrClause[i+1]=resStringLen+compAttrClause[i];
// 				allAttr[i+1]=compAttr[i];
// 			}
// 			allAttrClause[allAttrLen]=allLen;
// 			ret=InputMethodEvent_new(env,EVENT_TEXT_CHANGED,allClause,allClauseLen,allString,allSubStrings,
// 				allAttrLen,allAttrClause,allAttr,resStringLen,cursorPos,cursorPos);
// 
// 			delete[] allSubStrings;
// 			delete[] allClause;
// 			delete[] allAttr;
// 			delete[] allAttrClause;
// 		}
// 	}
// 
// 	delete[] resSubStrings;
// 	delete[] compSubStrings;
// 	delete[] resClause;
// 	delete[] compClause;
// 	delete[] compAttr;
// 	delete[] compAttrClause;
// 
// 	return ret;
// }
// 
// BOOL IMESetWindow(JNIEnv *env,BOOL pass)
// {
// 	COMPOSITIONFORM CompForm={0};
// 	CompForm.dwStyle=CFS_POINT;
// 
// 	do
// 	{
// 		if(pass)
// 		{
// 			CompForm.dwStyle=CFS_DEFAULT;
// 			break;
// 		}
// 		if(g_PassiveInputMethodRequests==NULL)
// 			break;
// 
// 		if(g_PassiveInputMethodRequests_class==NULL)
// 		{
// 			jclass t=env->GetObjectClass(g_PassiveInputMethodRequests);
// 			if(t==NULL)
// 				return FALSE;
// 			g_PassiveInputMethodRequests_class=env->NewGlobalRef(t);
// 		}
// 		if(g_PassiveInputMethodRequests_getCompositionLocation==NULL)
// 			g_PassiveInputMethodRequests_getCompositionLocation=env->GetMethodID(g_PassiveInputMethodRequests_class,
// 			g_PassiveInputMethodRequests_getCompositionLocation,"getCompositionLocation", "()[I");
// 
// 		jintArray compLoc=env->CallObjectMethod(g_PassiveInputMethodRequests,g_PassiveInputMethodRequests_getCompositionLocation);
// 		if(compLoc)
// 		{
// 			int len=env->GetArrayLength(len);
// 			jint pos[4]={0};
// 			if(len<2)
// 				break;
// 			if(len<4)
// 			{
// 				env->GetIntArrayRegion(compLoc,0,2,pos);
// 				CompForm.ptCurrentPos.x=pos[0];
// 				CompForm.ptCurrentPos.y=pos[1];
// 				break;
// 			}
// 			CompForm.dwStyle=CFS_RECT;
// 			env->GetIntArrayRegion(compLoc,0,4,pos);
// 			CompForm.ptCurrentPos.x=pos[0];
// 			CompForm.ptCurrentPos.y=pos[1];
// 			CompForm.rcArea.left=pos[0];
// 			CompForm.rcArea.top=pos[1];
// 			CompForm.rcArea.right=pos[0]+pos[2];
// 			CompForm.rcArea.bottom=pos[1]+pos[3];
// 		}
// 	}while(0)
// 
// 	return ImmSetCompositionWindow(g_hImc,&CompForm);
// }

JNIEXPORT jobject JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_peekMessageNative
(JNIEnv *env, jobject)
{
	jobject ret=NULL;

	if(g_bMouseEvent_return)
	{
		env->DeleteGlobalRef(g_MouseEvent);
		g_MouseEvent=NULL;
		g_bMouseEvent_return=FALSE;
	}
	else if(g_MouseEvent)
	{
		g_bMouseEvent_return=TRUE;
		return g_MouseEvent;
	}

	if(g_bUpdate)
	{
		g_bUpdate=FALSE;
		return ApplicationEvent_new(env,EVENT_UPDATE);
	}

	if(g_iWndState)
	{
		ret=ApplicationEvent_new(env,g_iWndState);
		g_iWndState=0;
		return ret;
	}

	POINT posScreen;
	GetCursorPos(&posScreen);
	if(g_bLButtonDown)
	{
		POINT posRelat={
			posScreen.x-g_WndPos.x,
			posScreen.y-g_WndPos.y,
		};

		if ( posScreen.x != g_WndPos.x || posScreen.y != g_WndPos.y )
		{
			RECT rc;
			GetWindowRect(g_hWnd, &rc);
			SetWindowPos(g_hWnd, 0, posRelat.x + rc.left, posRelat.y + rc.top, rc.right - rc.left, rc.bottom - rc.top,SWP_NOSENDCHANGING|SWP_NOSIZE|SWP_NOZORDER);
			g_WndPos.x = posScreen.x;
			g_WndPos.y = posScreen.y;
		}

		if ( GetAsyncKeyState(VK_LBUTTON) == 0)
			g_bLButtonDown = FALSE;
	}
	else
	{
		BOOL bHitTest=FALSE;
		if(g_hWnd==WindowFromPoint(&posScreen))
		{
			RECT rcClient;
			GetClientRect(g_hWnd,&rcClient);
			RECT rcClientAdjust=rcClient;
			AdjustWindowRect(&rcClientAdjust,g_dwStyle,g_hMenu!=NULL);
			RECT rc;
			GetWindowRect(g_hWnd,&rc);
			rcClient.left=rc.left-rcClientAdjust.left;
			rcClient.top=rc.top-rcClientAdjust.top;

			if(posScreen.x>=rcClient.left && 
				posScreen.x<rcClient.left+rcClient.right &&
				posScreen.y>=rcClient.top &&
				posScreen.y<rcClient.top+rcClient.bottom)
				bHitTest=TRUE;
		}

		if(bHitTest==FALSE && g_bHitTestLast)
			ret=MouseEvent_new(env,EVENT_MOUSE_EXITED,0,0,0,0,FALSE,0);
		else
		if(bHitTest && g_bHitTestLast==FALSE)
			ret=MouseEvent_new(env,EVENT_MOUSE_ENTERED,0,0,0,0,FALSE,0);

		g_bHitTestLast=bHitTest;
		if(ret)
			return ret;
	}

	while(1)
	{
		g_pMsg=NULL;
		if(PeekMessage(&g_Msg,NULL,0,0,1))
			g_pMsg=&g_Msg;
		else
		{
			GetKeyboardState(g_KeyState);
			return NULL;
		}

		switch(g_pMsg->message)
		{
		case MSG_SHOWCURSOR:
			g_bCursorHide=(g_pMsg->wParam==FALSE);
			break;
		case WM_LBUTTONDOWN:
		case WM_LBUTTONDBLCLK:
			ret=OnMouseDown(env,1,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
			break;
		case WM_MBUTTONDOWN:
		case WM_MBUTTONDBLCLK:
			ret=OnMouseDown(env,2,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
			break;
		case WM_RBUTTONDOWN:
		case WM_RBUTTONDBLCLK:
			ret=OnMouseDown(env,3,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
			break;
		case WM_LBUTTONUP:
			ret=OnMouseUp(env,1,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),g_pMsg->wParam);
			break;
		case WM_MBUTTONUP:
			ret=OnMouseUp(env,2,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),g_pMsg->wParam);
			break;
		case WM_RBUTTONUP:
			ret=OnMouseUp(env,3,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),g_pMsg->wParam);
			break;
		case WM_MOUSEWHEEL:
			ret=OnMouseWheel(env,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),LOWORD(g_pMsg->wParam),(short)HIWORD(g_pMsg->wParam));
			break;
		case WM_IME_NOTIFY:
			OnImeNotify(env,g_pMsg->wParam,g_pMsg->lParam);
			break;
		case MSG_QUIT_REQUESTED:
			ret = ApplicationEvent_new(env, EVENT_QUIT_REQUESTED);
			break;
		case MSG_ACTIVATED:
			ret = ApplicationEvent_new(env, EVENT_ACTIVATED);
			break;
		case MSG_DEACTIVATED:
			ret = ApplicationEvent_new(env, EVENT_DEACTIVATED);
			break;
		case MSG_IME_ENABLE:
			ImeEnable(g_pMsg->wParam);
			break;
		case MSG_DSHOW_EVENT:
			DShowEvent();
			break;
		case MSG_SETCURSOR:
			SetCursor(g_pMsg->lParam);
			break;
		case aaaaaaaa0xC07A:
		case aaaaaaaa0xC07B:
			ret=OnMouseWheel(env,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),0,(short)HIWORD(g_pMsg->wParam));
			break;
		case WM_MOUSEMOVE:
			ret=OnMouseMove(env,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam),g_pMsg->wParam);
			break;
		case WM_KEYDOWN:
		case WM_SYSKEYDOWN:
			ret=OnKeyEvent(env,g_pMsg->wParam,EVENT_KEY_PRESSED);
			break;
		case WM_KEYUP:
		case WM_SYSKEYUP:
			ret=OnKeyEvent(env,g_pMsg->wParam,EVENT_KEY_RELEASED);
			break;
		case WM_SYSCHAR:
			ret=OnKeyChar(env,g_pMsg->wParam,HIWORD(g_pMsg->lParam),TRUE);
			break;
		case WM_CHAR:
			ret=OnKeyChar(env,g_pMsg->wParam,HIWORD(g_pMsg->lParam),FALSE);
			break;
		case WM_IME_COMPOSITION:
			ret=ImeComposition(env,LOWORD(g_pMsg->wParam),g_pMsg->lParam);
			break;
		case WM_IME_STARTCOMPOSITION:
			if(g_bIMEActiveMode==NULL)
				IMESetWindow(env,g_bIMEPassiveMode);
			break;
		case WM_IME_ENDCOMPOSITION:
			break;
		case WM_COMMAND:
			if(HIWORD(g_pMsg->wParam)==0)//MENU
			{
				
			}
			break;
		case WM_NCLBUTTONDOWN:
			if(!(g_pMsg->wParam>=HTSIZEFIRST && g_pMsg->wParam<=HTSIZELAST))
			{
				if(g_bDisplayMode)
					ret=OnMouseDown(env,1,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
				else
				{
					g_WndPos.x=GET_X_LPARAM(g_pMsg->lParam);
					g_WndPos.y=GET_Y_LPARAM(g_pMsg->lParam);
					g_bLButtonDown=TRUE;
					SetActiveWindow(g_hWnd);
				}
			}
			break;
		case WM_NCMBUTTONDOWN:
			if(g_bDisplayMode && !(g_pMsg->wParam>=HTSIZEFIRST && g_pMsg->wParam<=HTSIZELAST))
				ret=OnMouseDown(env,2,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
			break;
		case WM_NCRBUTTONDOWN:
			if(g_bDisplayMode && !(g_pMsg->wParam>=HTSIZEFIRST && g_pMsg->wParam<=HTSIZELAST))
				ret=OnMouseDown(env,3,GET_X_LPARAM(g_pMsg->lParam),GET_Y_LPARAM(g_pMsg->lParam));
			break;
		}

		if(MyGetMessage(g_pMsg))
		{
			TranslateMessage(g_pMsg);
			DispatchMessage(g_pMsg);
		}
		if(ret)
			return ret;
	}
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_dispatchMessageNative
(JNIEnv *, jobject)
{
	if(g_pMsg)
	{
		if(MyGetMessage(g_pMsg))
		{
			TranslateMessage(g_pMsg);
			DispatchMessage(g_pMsg);
		}
	}
}

// jobject PixelFormat_new(JNIEnv* env)
// {
// 	jclass PixelFormat_class=env->FindClass("keel/gfx/PixelFormat");
// 	jmethodID PixelFormat_init=env->GetMethodID(PixelFormat_class,"<init>", "(JIIIIIIIIIIII)V");
// 
// 	PIXELFORMATDESCRIPTOR ppfd={0};
// 	ppfd.nSize = sizeof(ppfd);
// 	ppfd.nVersion = 1;
// 	++g_PixelFormatId;
// 	if ( DescribePixelFormat(g_hDC, g_PixelFormatId, sizeof(ppfd), &ppfd) )
// 	{
// 		while ( (!(ppfd.dwFlags & PFD_GENERIC_FORMAT) || (ppfd.dwFlags & PFD_GENERIC_ACCELERATED))
// 			&& !(ppfd.dwFlags & PFD_DRAW_TO_BITMAP)
// 			&& ppfd.dwFlags & PFD_DOUBLEBUFFER
// 			&& ppfd.iPixelType != 1)
// 		{
// 			ZeroMemory(&ppfd,sizeof(ppfd));
// 			ppfd.nSize = sizeof(ppfd);
// 			ppfd.nVersion = 1;
// 			++g_PixelFormatId;
// 			if ( !DescribePixelFormat(g_hDC, g_PixelFormatId, sizeof(ppfd), &ppfd) )
// 			{
// 				ReleaseDC(g_hWnd, g_hDC);
// 				return 0;
// 			}
// 		}
// 		return env->NewObject(PixelFormat_class, PixelFormat_init,g_PixelFormatId,ppfd.cColorBits,
// 			ppfd.cRedBits,ppfd.cGreenBits,ppfd.cBlueBits,ppfd.cAlphaBits,ppfd.cDepthBits,
// 			ppfd.cAccumBits,ppfd.cAccumRedBits,ppfd.cAccumGreenBits,ppfd.cAccumBlueBits,
// 			ppfd.cAccumAlphaBits,ppfd.cStencilBits);
// 	}
// 	else
// 	{
// 		ReleaseDC(g_hWnd, g_hDC);
// 		return 0;
// 	}
// }

// jobject PixelFormat_new2(JNIEnv *env)
// {
// 	jclass PixelFormat_class=env->FindClass("keel/gfx/PixelFormat");
// 	jmethodID PixelFormat_init=env->GetMethodID(PixelFormat_class,"<init>", "(JIIIIIIIIIIIII)V");
// 	return env->NewObject(PixelFormat_class, PixelFormat_init,(jlong)2,16,5,5,5,5,16,0,0,0
// 		0,0,0,0);
// }

// JNIEXPORT jobjectArray JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1getPixelFormatList
// (JNIEnv *env, jobject)
// {
// 	g_PixelFormatId = 0;
// 	if(g_hWnd==NULL)
// 		return NULL;
// 
// 	jobject pfList[100];
// 	int i;
// 	for(i=0;i<99;++i)
// 	{
// 		jobject t=PixelFormat_new(env);
// 		if(t==NULL)
// 			break;
// 		pfList[i]=t;
// 	}
// 	pfList[i++]=PixelFormat_new2(env);
// 	jobjectArray ret=env->NewObjectArray(i,env->FindClass("keel/gfx/PixelFormat"),NULL);
// 	for(int j=0;j<i;++j)
// 		env->SetObjectArrayElement(ret,j,pfList[j]);
// 	return ret;
// }

// void SetObjectDisplayMode(JNIEnv *env, jobject o)
// {
// 	jclass o_class=env->GetObjectClass(o);
// 	jfieldID o_displaymode=env->GetFieldID(o_class,"displaymode", "Lkeel/runtime/DisplayMode;");
// 	jclass DisplayMode_class=env->FindClass("keel/runtime/DisplayMode");
// 	jfieldID DisplayMode_width=env->GetFieldID(DisplayMode_class,"width", "I");
// 	jfieldID DisplayMode_height=env->GetFieldID(DisplayMode_class,"height", "I");
// 	jfieldID DisplayMode_bitdepth=env->GetFieldID(DisplayMode_class,"bitdepth", "I");
// 	jfieldID DisplayMode_refreshrate=env->GetFieldID(DisplayMode_class,"refreshrate", "I");
// 
// 	DEVMODE DevMode;
// 	EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &DevMode);
// 
// 	jobject DisplayMode=env->GetObjectField(o,o_displaymode);
// 	env->SetIntField(DisplayMode,DisplayMode_width,DevMode.dmPelsWidth);
// 	env->SetIntField(DisplayMode,DisplayMode_height,DevMode.dmPelsHeight);
// 	env->SetIntField(DisplayMode,DisplayMode_bitdepth,DevMode.dmBitsPerPel);
// 	env->SetIntField(DisplayMode,DisplayMode_refreshrate,DevMode.dmDisplayFrequency);
// }

JNIEXPORT jobjectArray JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl__1getDisplayModeList
(JNIEnv *env, jobject o)
{
// 	jclass KeelRuntimeWindowsImpl_class=env->FindClass("backstage/runtime/KeelRuntimeWindowsImpl");
// 	jfieldID KeelRuntimeWindowsImpl_gl_vendor=env->GetStaticFieldID(KeelRuntimeWindowsImpl_class,"gl_vendor", "Ljava/lang/String;");
// 	jstring gl_vendor=env->GetStaticObjectField(KeelRuntimeWindowsImpl_class,KeelRuntimeWindowsImpl_gl_vendor);
// 	env->ReleaseBooleanArrayElements()
	SetObjectDisplayMode(env,o);
	jclass DisplayMode_class=env->FindClass("keel/runtime/DisplayMode");
	jmethodID DisplayMode_init=env->GetMethodID(DisplayMode_class, "<init>", "(IIII)V");
	int n=0;
	DEVMODE DevMode;
	while(EnumDisplaySettings(NULL,n,&DevMode))++n;
	jobjectArray ret=env->NewObjectArray(n,DisplayMode_class,NULL);
	for(int i=0;i<n;++i)
	{
		EnumDisplaySettings(NULL,i,&DevMode);
		env->SetObjectArrayElement(ret,i,env->NewObject(DisplayMode_class,DisplayMode_init,
			DevMode.dmPanningWidth,DevMode.dmPanningHeight,DevMode.dmBitsPerPel,DevMode.dmDisplayFrequency));
	}
	return ret;
}

// void IMEFree(HWND hWnd)
// {
// 	if(g_hImc)
// 		ImmDestroyContext(g_hImc);
// 	g_hIMENotifyWnd=NULL;
// 	ImmAssociateContext(hWnd,NULL);
// }

// void WindowsFree()
// {
// 	if ( g_hWnd==NULL)
// 		return;
// 
// 	IMEFree(g_hWnd);
// 	if ( g_hDC )
// 	{
// 		ReleaseDC(g_hWnd, g_hDC);
// 		g_hDC = NULL;
// 	}
// 	if ( g_cont )
// 	{
// 		wglMakeCurrent(0, 0);
// 		wglDeleteContext(g_cont);
// 		g_cont = NULL;
// 	}
// 	if ( g_windowName )
// 	{
// 		RemoveProp(g_hWnd, g_windowName);
// 		delete[] g_windowName;
// 		g_windowName = NULL;
// 	}
// 	DestroyWindow(g_hWnd);
// 	g_hWnd = NULL;
// 	g_hCursor = NULL;
// }

// void ImeCreate(HWND hWnd)
// {
// 	g_hIMENotifyWnd=hWnd;
// 	g_hImc=ImmCreateContext();
// 	ImmAssociateContext(hWnd,g_bIMEEnable);
// 	RECT rc,rcClient;
// 	GetWindowRect(hWnd,&rc);
// 	GetClientRect(hWnd,&rcClient);
// 	g_immPosRelatX=GetSystemMetrics(SM_CXFRAME);
// 	g_immPosRelatY=rc.bottom-rc.top-(rcClient.bottom-rcClient.top)-GetSystemMetrics(SM_CYFRAME);
// }

// JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createWindowNative
// (JNIEnv *env, jobject, jstring winName, jint width, jint height)
// {
// 	if(g_iRuntimeState==0)
// 		return;
// 
// 	if(g_bDisplayMode)
// 	{
// 		//
// 	}
// 	else
// 	{
// 		WindowsFree();
// 	}
// 	
// 	TCHAR *pname=_T("");
// 	if(winName)
// 	{
// 		jchar *s=env->GetStringChars(winName,NULL);
// 		int len=env->GetStringLength(winName)+1;
// 		pname=new TCHAR[len];
// 		_tcscpy_s(pname,len,s);
// 		env->ReleaseStringChars(winName,s);
// 	}
// 
// 	RECT rc={0,0,width,height};
// 	
// 	g_dwStyle=WS_CAPTION|WS_SYSMENU;
// 	AdjustWindowRect(&rc,g_dwStyle,g_hMenu!=NULL);
// 	HWND hWnd=CreateWindow(_T("runtimetest_win"),pname,g_dwStyle,CW_USEDEFAULT,CW_USEDEFAULT,
// 		rc.right-rc.left,rc.bottom-rc.top,NULL,NULL,g_hInstance,NULL);
// 	if(g_windowName)
// 	{
// 		delete[] g_windowName;
// 		g_windowName=NULL;
// 	}
// 	int len=_tcslen(pname)+50;
// 	g_windowName=new TCHAR[len];
// 	_stprintf_s(g_windowName,len,_T("KeelRuntimeWindow_%s"),pname);
// 	if(winName)
// 		delete[] pname;
// 	SetProp(hWnd,g_windowName,HANDLE_FLAG_INHERIT);
// 	
// 	if(g_hMenu)
// 		SetMenu(g_hMenu);
// 
// 	g_bDisplayMode=FALSE;
// 	g_hWnd=hWnd;
// 	g_hCursor=LoadCursor (NULL, IDC_ARROW) ;
// 	g_hDC=GetDC(g_hWnd);
// 	ImeCreate(hWnd);
// 	SetNotifyWindow(g_hWnd);
// 	if(g_hIcon)
// 	{
// 		SendMessage(g_hWnd,WM_SETICON,0,g_hIcon);
// 		SendMessage(g_hWnd,WM_SETICON,1,g_hIcon);
// 	}
// 	ShowWindow(g_hWnd,SW_SHOW);
// 	SetForegroundWindow(g_hWnd);
// }

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createDisplayNative
(JNIEnv *, jobject, jobject)
{
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_disposeDisplayNative
(JNIEnv *, jobject)
{
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_postDummyMessage
(JNIEnv *, jobject)
{
	PostMessage(g_hWnd,MSG_DUMMY,NULL,NULL);
}

JNIEXPORT void JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_createControllerMenuNative
(JNIEnv *, jobject, jint, jintArray, jobjectArray)
{

}
JNIEXPORT jint JNICALL Java_backstage_runtime_KeelRuntimeWindowsImpl_getDirectXVersion
(JNIEnv *, jclass)
{
	return 8;
}

